package com.dji.GSDemo.GaodeMap;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.dji.GSDemo.GaodeMap.UploadPicture.UAVPictureUploadListener;
import com.dji.GSDemo.GaodeMap.UploadPicture.UAVUploadPicture;

import java.util.ArrayList;
import java.util.Collection;

import dji.common.error.DJIError;
import dji.common.mission.waypoint.Waypoint;
import dji.common.mission.waypoint.WaypointExecutionProgress;
import dji.common.mission.waypoint.WaypointMission;
import dji.common.mission.waypoint.WaypointMissionDownloadEvent;
import dji.common.mission.waypoint.WaypointMissionExecuteState;
import dji.common.mission.waypoint.WaypointMissionExecutionEvent;
import dji.common.mission.waypoint.WaypointMissionFinishedAction;
import dji.common.mission.waypoint.WaypointMissionFlightPathMode;
import dji.common.mission.waypoint.WaypointMissionHeadingMode;
import dji.common.mission.waypoint.WaypointMissionUploadEvent;
import dji.common.util.CommonCallbacks;
import dji.sdk.mission.waypoint.WaypointMissionOperator;
import dji.sdk.mission.waypoint.WaypointMissionOperatorListener;
import dji.sdk.sdkmanager.DJISDKManager;


public class WayPointMissionController {

    private WaypointMissionListener listener;

    private WaypointMissionOperator missionOperatorInstance;
    public static WaypointMission.Builder waypointMissionBuilder;

    private ArrayList<Waypoint> waypointList = new ArrayList<Waypoint>();

    private float mSpeed = 10.0f;
    private WaypointMissionFinishedAction mFinishedAction = WaypointMissionFinishedAction.GO_HOME;
    private WaypointMissionHeadingMode mHeadingMode = WaypointMissionHeadingMode.AUTO;

    private final UAVUploadPicture pictureUploader = UAVUploadPicture.getInstance();
    private boolean waitingPictureUploadCompleted = false;
    private final UAVPictureUploadListener pictureUploadListener = new UAVPictureUploadListener() {
        @Override
        public void onLog(String message) {

        }

        @Override
        public void onDownloadComplete() {
            if(waitingPictureUploadCompleted){
                try {
                    getWaypointMissionOperator().resumeMission(null);
                    getListener().log("resume mission");
                }catch (Exception e) {
                    getListener().log("onPictureDownloadComplete already resumeMission");
                }
                waitingPictureUploadCompleted = false;
            }
        }
    };

    private int waypointStep = -1;
    private int actionStep = -1;
    private final int maxPictureTransmission = 5;

    private static class Singleton {
        private static final WayPointMissionController instance = new WayPointMissionController();
    }

    public static WayPointMissionController getInstance() {
        return WayPointMissionController.Singleton.instance;
    }

    private WayPointMissionController() {
        if (getWaypointMissionOperator() != null) {
            getWaypointMissionOperator().addListener(eventNotificationListener);
        }
    }

    protected void finalize() {
        if (getWaypointMissionOperator() != null) {
            getWaypointMissionOperator().removeListener(eventNotificationListener);
        }
    }

    public void setListener(WaypointMissionListener listener) {
        this.listener = listener;
    }

    public void removeListener(WaypointMissionListener listener) {
        if (this.listener == listener) {
            this.listener = null;
        }
    }

    private WaypointMissionListener getListener() {
        if (listener != null) return listener;
        else return emptyWaypointMissionListener;
    }

    public interface WaypointMissionListener extends WaypointMissionOperatorListener {
        void onConfigMission(boolean success);

        void onLoadMission(DJIError error);

        void onUploadMission(DJIError error, boolean isRetrying);

        void onStartMission(DJIError error);

        void onStopMission(DJIError error);

        void onWaypointTargetChanged(int target);

        void log(String msg);
    }

    private final WaypointMissionOperatorListener eventNotificationListener = new WaypointMissionOperatorListener() {
        @Override
        public void onDownloadUpdate(WaypointMissionDownloadEvent downloadEvent) {
            getListener().onDownloadUpdate(downloadEvent);
        }

        @Override
        public void onUploadUpdate(WaypointMissionUploadEvent uploadEvent) {
            getListener().onUploadUpdate(uploadEvent);
        }

        @Override
        public void onExecutionUpdate(WaypointMissionExecutionEvent executionEvent) {
            updateStep(executionEvent.getProgress());
            getListener().onExecutionUpdate(executionEvent);
        }

        @Override
        public void onExecutionStart() {
            getListener().onExecutionStart();
        }

        @Override
        public void onExecutionFinish(@Nullable final DJIError error) {
            getListener().onExecutionFinish(error);
        }
    };

    private void updateStep(WaypointExecutionProgress progress) {
        if (progress == null || progress.executeState != WaypointMissionExecuteState.BEGIN_ACTION)
            return;
        int newStep = progress.targetWaypointIndex;
        if (newStep > waypointStep) {
            waypointStep = newStep;
            actionStep = -1;
            if(pictureUploader.download_all()>0){
                getWaypointMissionOperator().pauseMission(null);
                waitingPictureUploadCompleted = true;
                getListener().log("upload picture and pause mission");
            }
        }
        actionStep++;
        getListener().log("waypointStep:"+waypointStep+"actionStep:"+actionStep);
//        if (actionStep == 2){
//            if(pictureDownloadId == -1 || pictureDownloadedId >= pictureDownloadId){
//                pictureDownloadId = pictureUploader.download_all();
//            }
//        }
    }

    private WaypointMissionOperator getWaypointMissionOperator() {
        if (missionOperatorInstance == null) {
            missionOperatorInstance = DJISDKManager.getInstance().getMissionControl().getWaypointMissionOperator();
        }
        return missionOperatorInstance;
    }

    private WaypointMission.Builder getWaypointMissionBuilder() {
        if (waypointMissionBuilder == null)
            waypointMissionBuilder = new WaypointMission.Builder();
        return waypointMissionBuilder;
    }

    public void setMissionPara(float mSpeed, WaypointMissionFinishedAction mFinishedAction, WaypointMissionHeadingMode mHeadingMode) {
        this.mSpeed = mSpeed;
        this.mFinishedAction = mFinishedAction;
        this.mHeadingMode = mHeadingMode;
    }

    public void setWaypoints(Collection<Waypoint> waypointList) {
        this.waypointList.clear();
        getWaypointMissionBuilder().waypointList(this.waypointList).waypointCount(waypointList.size());
        this.waypointList.addAll(waypointList);
    }

    public void addWaypoint(Waypoint waypoint) {
        waypointList.add(waypoint);
    }

    public boolean configMission() {
        getWaypointMissionBuilder().waypointList(waypointList).waypointCount(waypointList.size());

        if (waypointMissionBuilder == null) {
            waypointMissionBuilder = new WaypointMission.Builder().finishedAction(mFinishedAction)
                    .headingMode(mHeadingMode)
                    .autoFlightSpeed(mSpeed)
                    .maxFlightSpeed(mSpeed)
                    .flightPathMode(WaypointMissionFlightPathMode.NORMAL);

        } else {
            waypointMissionBuilder.finishedAction(mFinishedAction)
                    .headingMode(mHeadingMode)
                    .autoFlightSpeed(mSpeed)
                    .maxFlightSpeed(mSpeed)
                    .flightPathMode(WaypointMissionFlightPathMode.NORMAL);
        }

        boolean success = waypointMissionBuilder.getWaypointList().size() > 0;
        getListener().onConfigMission(success);
        return success;
    }

    public boolean loadMission() {
        DJIError error = getWaypointMissionOperator().loadMission(waypointMissionBuilder.build());
        getListener().onLoadMission(error);
        return error == null;
    }

    public void uploadAndStartMission() {
        getWaypointMissionOperator().uploadMission(new CommonCallbacks.CompletionCallback() {
            @Override
            public void onResult(DJIError error) {
                getListener().onUploadMission(error, true);
                if (error == null) {
                    startMission();
                } else {
                    getWaypointMissionOperator().retryUploadMission(new CommonCallbacks.CompletionCallback() {
                        @Override
                        public void onResult(DJIError error) {
                            getListener().onUploadMission(error, false);
                            if (error == null) {
                                startMission();
                            }
                        }
                    });
                }
            }
        });
    }

    public void startMission() {
        waypointStep = -1;
        getWaypointMissionOperator().startMission(error -> listener.onStartMission(error));
    }


    public void stopMission() {
        getWaypointMissionOperator().stopMission(error -> getListener().onStopMission(error));
    }

    WaypointMissionListener emptyWaypointMissionListener = new WaypointMissionListener() {
        @Override
        public void onDownloadUpdate(@NonNull WaypointMissionDownloadEvent waypointMissionDownloadEvent) {

        }

        @Override
        public void onUploadUpdate(@NonNull WaypointMissionUploadEvent waypointMissionUploadEvent) {

        }

        @Override
        public void onExecutionUpdate(@NonNull WaypointMissionExecutionEvent waypointMissionExecutionEvent) {

        }

        @Override
        public void onExecutionStart() {

        }

        @Override
        public void onExecutionFinish(@Nullable DJIError djiError) {

        }

        @Override
        public void onWaypointTargetChanged(int target) {

        }

        @Override
        public void log(String msg) {

        }

        @Override
        public void onConfigMission(boolean success) {

        }

        @Override
        public void onLoadMission(DJIError error) {

        }

        @Override
        public void onUploadMission(DJIError error, boolean isRetrying) {

        }

        @Override
        public void onStartMission(DJIError error) {

        }

        @Override
        public void onStopMission(DJIError error) {

        }
    };
}